<?php
/**
 * Created by PhpStorm.
 * User: peter
 * Date: 2018/7/3
 * Time: 上午9:23
 */

namespace app\mall\logic;

use app\model\Distribution;
use app\model\Order;
use app\model\OrderAttach;
use app\model\OrderProcess;
use app\model\UpgradeAgentOrder;
use extend\Functions;
use extend\STATUS_CODE;
use extend\WeChatTemplateMessage;
use Naixiaoxin\ThinkWechat\Facade;
use think\facade\Log;

class Pay
{
    /**
     * @purpose 微信支付升级代理商同步回调
     * @param string $order_no
     * @param int $uid
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \think\Exception
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function wechatUpgradeAgentSync (string $order_no, int $uid)
    {
        $order          = new UpgradeAgentOrder();
        $member         = new \app\model\Member();
        $member->startTrans();
        $member_info     = $member
            ->where('uid', $uid)
            ->field('uid,agent_end_time,agent')
            ->find();
        if (!$member_info || $order->where('order_no', $order_no)->count(1) < 1){
            $order->rollback();
            return Functions::result(
                STATUS_CODE::FAIL,
                '无效的订单号!'
            );
        }
        // 主动查询订单是否支付成功
        $app        =   Facade::payment('official_account');
        $pay_result =   $app->order->queryByOutTradeNumber($order_no);
        if (
            $pay_result['return_code'] === 'SUCCESS' &&
            $pay_result['return_msg'] === 'OK' &&
            $pay_result['trade_state'] === 'SUCCESS' &&
            $pay_result['result_code'] === 'SUCCESS'
        ) {
            $order_info     = $order
                ->where([
                    'order_no'   => $pay_result['out_trade_no'],
                    'uid'           => $uid,
                ])
                ->lock(true)
                ->field('id,uid,order_no,is_pay')
                ->find();
            if (!$order_info) {
                $member->rollback();
                return Functions::result(
                    STATUS_CODE::FAIL,
                    '订单不存在!'
                );
            }
            if ($order_info->is_pay === 2) {
                $member->commit();
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    '支付成功!'
                );
            }
            // 更新用户数据
            $agent_end_time = 0;
            if ($member_info->agent_end_time === 0) {
                $agent_end_time = strtotime(date('Y-m-d',time() + (3600 * 24 * 365)).' 00:00:00');
            } else {
                $agent_end_time = strtotime(date('Y-m-d',$member_info->agent_end_time + (3600 * 24 * 365)).' 00:00:00');
            }
            // 如果代理商已经到期则重新计算时间
            if ($member_info->agent === 1) {
                $agent_end_time = strtotime(date('Y-m-d',time() + (3600 * 24 * 365)).' 00:00:00');
            } else {
                $agent_end_time = strtotime(date('Y-m-d',$member_info->agent_end_time + (3600 * 24 * 365)).' 00:00:00');
            }

            // 如果代理商已经到期则重新计算时间
            if ($member_info->agent === 1) {
                $agent_end_time = strtotime(date('Y-m-d',time() + (3600 * 24 * 365)).' 00:00:00');
            } else {
                $agent_end_time = strtotime(date('Y-m-d',$member_info->agent_end_time + (3600 * 24 * 365)).' 00:00:00');
            }
            $member_result  = $member
                ->save([
                    'agent' => 2,
                    'agent_end_time' => $agent_end_time
                ], ['uid' => $uid]);
            // 更新订单状态
            $start_time = $member_info->agent_end_time ? $member_info->agent_end_time : strtotime(date('Y-m-d', time()).' 00:00:00');
            $end_time   = strtotime(date('Y-m-d', $start_time + (3600 * 24 * 365)).' 00:00:00');
            $order_result   = $order
                ->save([
                    'pay_time'  => strtotime($pay_result['time_end']),
                    'pay_money' => $pay_result['cash_fee'],
                    'pay_no'    => $pay_result['transaction_id'],
                    'pay_type'  => 1,
                    'is_pay'    => 2,
                    'start_time'=> $start_time,
                    'end_time'  => $end_time
                ], ['order_no' => $order_info->order_no]);
            if ($order_result && $member_result) {
                $member->commit();
                \app\mall\logic\Distribution::agentUpgrade($order_info->order_no, $uid);
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    '支付成功'
                );
            }
            $member->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                $pay_result['trade_state_desc']
            );
        }
        $member->rollback();
        return Functions::result(
            STATUS_CODE::PARAMETER_ERROR,
            $pay_result['trade_state_desc']
        );

    }
    /**
     * @purpose 支付升级代理商
     * @param int $uid
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function payUpgradeAgent (int $uid): array
    {
        $model                      = new UpgradeAgentOrder();
        $member         = new \app\model\Member();
        $model->startTrans();

        $member_info    = $member
            ->with('wechat')
            ->where('uid', $uid)
            ->field('uid,uuid')
            ->find();
        if (!$member_info) {
            $model->rollback();
            return  Functions::result(
                STATUS_CODE::FAIL,
                '用户不存在!'
            );
        }
        $agent_upgrade_info         = Configure::getConfigure('agent_upgrade');
        $agent_upgrade_info         = $agent_upgrade_info['data'];
        $order_info                 = [];
        $order_info['uid']          = $uid;
        $order_info['order_no']     = md5(date('YmdHis').Functions::random(50));
        RE_ORDER_NO:
            $order_info['order_no']     = md5(date('YmdHis').Functions::random(50));
        if ($model->where('order_no', $order_info['order_no'])->count(1) > 0) {
            goto RE_ORDER_NO;
        }

        $data = [
            'body'          => 'V奢商城-升级代理商!',
            'trade_type'    => 'JSAPI',
            'out_trade_no'  => $order_info['order_no'],
            'total_fee'     => (int) ($agent_upgrade_info['pay'] * 100),
            'openid'        => $member_info->openid,
            'attach'        => $member_info->uuid,
            'notify_url'    => rtrim(config('app.client_domain'), '/').'/api/pay.agent.upgrade.async'
        ];
        $app        = Facade::payment('official_account');
        $result = $app->order->unify($data);
        $result = $app->jssdk->sdkConfig($result['prepay_id']);
        $result['timeStamp'] = $result['timestamp'];
        unset($result['timestamp']);
        $order_result = $model
            ->data($order_info)
            ->save();
        if ($order_result) {
            $model->commit();
            return Functions::result(
                STATUS_CODE::SUCCESS,
                [
                    'voucher' => $result,
                    'order_no' => $order_info['order_no']
                ]
            );
        }
        $model->rollback();
        return Functions::result(
            STATUS_CODE::CREATE_FAIL,
            '订单创建失败!'
        );
    }
    /**
     * @purpose 支付
     * @param string $order_no
     * @param int $pay_type
     * @param int $uid
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public static function pay (string $order_no, int $pay_type, int $uid): array
    {
        if (!$order_no) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '缺少订单号!'
            );
        }
//        if (!in_array($pay_type, [1, 2])) {
        if ($pay_type !== 1) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '未知的支付方式!'
            );
        }
        $member         = new \app\model\Member();
        $member_info    = $member
            ->with('wechat')
            ->where('uid', $uid)
            ->field('uid,uuid')
            ->find();
        if (!$member_info) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '用户不存在!'
            );
        }
        $order          = new Order();
        $fields         = 'od.id,od.uid,od.status,od.order_no,sum(oa.goods_price * oa.number) as total_price';
        $order_info     = $order
//            ->fetchSql(true)
            ->alias('od')
            ->leftJoin('order_attach oa', 'od.id=oa.order_id')
            ->group('od.id')
            ->where(['od.order_no' => $order_no])
            ->field($fields)
            ->find();
        if (!$order_info) {
            return Functions::result(
                STATUS_CODE::FAIL,
                '订单不存在!'
            );
        }
        if ($order_info->status !== 1) {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '订单状态错误!'
            );
        }
        switch ($pay_type) {
            case 1: // 微信支付
                $voucher            = md5($order_info->order_no.Functions::random(50));
                RE_VOUCHER:
                $voucher            = md5($order_info->order_no.Functions::random(50));
                if ($order->total(['pay_voucher' => $voucher]) > 0) {
                    goto RE_VOUCHER;
                }
                $order->save(['pay_voucher' => $voucher], ['id' => $order_info->id]);
                $data = [
                    'body'          => 'V奢商城-商品交易!',
                    'trade_type'    => 'JSAPI',
                    'out_trade_no'  => $voucher,
                    'total_fee'     => $order_info->total_price,
                    'openid'        => $member_info->openid,
                    'attach'        => $member_info->uuid
                ];
                $app        = Facade::payment('official_account');
                $result = $app->order->unify($data);
                $result = $app->jssdk->sdkConfig($result['prepay_id']);
                $result['timeStamp'] = $result['timestamp'];
                unset($result['timestamp']);
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    [
                        'voucher' => $result
                    ]
                );
                break;
            default :
                return Functions::result(
                    STATUS_CODE::PARAMETER_ERROR,
                    '未知的支付方式!'
                );
                break;
        }
        //  return self::wechatSyncCallback($order_no, $pay_type);
    }

    /**
     * @purpose 微信支付同步回调
     * @param string $order_no
     * @param int $uid
     * @return array
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function wechatSyncCallback (string $order_no, int $uid): array
    {
        $order          =  new Order();
        $order->startTrans();
        $order_info     = $order
            ->where([
                'order_no'  => $order_no,
                'uid'       => $uid
            ])
            ->lock(true)
            ->field('id,uid,status,pay_voucher')
            ->find();
        if (!$order_info) {
            $order->rollback();
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                '无效的订单号!'
            );
        }
        if ($order_info->status === 2) {
            return Functions::result(
                STATUS_CODE::ORDER_STATUS_ERROR,
                '支付成功!'
            );
        }
        if ($order_info->status !== 1) {
            return Functions::result(
                STATUS_CODE::ORDER_STATUS_ERROR,
                '订单状态错误!'
            );
        }
        // 主动查询订单是否支付成功
        $app        =   Facade::payment('official_account');
        $pay_result =   $app->order->queryByOutTradeNumber($order_info->pay_voucher);
        if (
            $pay_result['return_code'] === 'SUCCESS' &&
            $pay_result['return_msg'] === 'OK' &&
            $pay_result['trade_state'] === 'SUCCESS' &&
            $pay_result['result_code'] === 'SUCCESS'
        ) {
            $order_info     = $order
                ->where([
                    'pay_voucher'   => $pay_result['out_trade_no'],
                    'uid'           => $uid,
                ])
                ->field('id,uid,status,order_no')
                ->find();
            if (!$order_info) {
                return Functions::result(
                    STATUS_CODE::FAIL,
                    '订单未找到!'
                );
            }
            if ($order_info->status === 2) {
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    '支付成功!'
                );
            }

            $update_data    = [];
            $update_data['status']      = 2;
            $update_data['pay_time']    = strtotime($pay_result['time_end']);
            $update_data['pay_money']   = $pay_result['cash_fee'];
            $update_data['pay_no']      = $pay_result['transaction_id'];
            $update_data['pay_type']    = 1;
            $order_process  = new OrderProcess();
            // 更新订单状态
            $order_result = $order
                ->isUpdate(true)
                ->save($update_data, ['id' => $order_info->id]);
            // 记录订单流程
            $order_process_result =
                $order_process
                    ->isUpdate(false)
                    ->data([
                        'order_id'      => $order_info->id,
                        'status'        => 2,
                        'operator_id'   => $order_info->uid,
                        'operator_type' => 1,
                        'description'   => '订单支付成功'
                    ])
                    ->save();
            if ($order_result && $order_process_result) {
                $order->commit();
                self::distribution($order_no);
                return Functions::result(
                    STATUS_CODE::SUCCESS,
                    '支付成功'
                );
            }
            $order->rollback();
            return Functions::result(
                STATUS_CODE::FAIL,
                '系统错误！'
            );
        } else {
            return Functions::result(
                STATUS_CODE::PARAMETER_ERROR,
                $pay_result['trade_state_desc']
            );
        }
    }

    /**
     * @purpose 微信支付异步回调
     * @return \Symfony\Component\HttpFoundation\Response
     * @throws \EasyWeChat\Kernel\Exceptions\Exception
     */
//    public static function wechatAsyncCallback (): array
//    {
//
//    }

    /**
     * @purpose 分销
     * @param string $order_no
     * @return bool
     * @throws \EasyWeChat\Kernel\Exceptions\HttpException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidArgumentException
     * @throws \EasyWeChat\Kernel\Exceptions\InvalidConfigException
     * @throws \Psr\SimpleCache\InvalidArgumentException
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     * @throws \think\exception\PDOException
     */
    public static function distribution (string $order_no)
    {
        // 获取分销比例配置
        $ratio      =   Configure::getConfigure('distribution_ratio');
        if (!$ratio['data']) {
            return false;
        }
        if (!$ratio['data']['switch']) {
            return false;
        }
        $ratio = $ratio['data'];
        $order              =   new Order();
        $order_attach       =   new OrderAttach();
        $distribution       =   new Distribution();
        $member             =   new \app\model\Member();
        // 获取订单信息
        $order_info =
            $order
                ->alias('od')
                ->join('member mb', 'od.uid=mb.uid')
                ->where(['od.order_no' => $order_no])
                ->field('od.id as order_id,od.uid,od.status,od.order_no,od.pay_money,od.is_distribution,mb.invitation_from,FROM_UNIXTIME(od.create_at, \'%Y-%m-%d %H:%i:%s\') as create_date,FROM_UNIXTIME(od.create_at + 604800, \'%Y-%m-%d %H:%i:%s\') as expect_income_date')
                ->find();
        $member_info = $member
            ->where('uid', $order_info->uid)
            ->field('uid,nickname')
            ->find();
        if (!$order_info) {
            return false;
        }
        if ($order_info->invitation_from === 'self' || $order_info->is_distribution === 2) {
            return false;
        }
        $order_goods = $order_attach
            ->alias('oa')
            ->join('goods g', 'oa.goods_id=g.id')
            ->where('oa.order_id', $order_info->order_id)
            ->field('oa.goods_id,oa.goods_number,oa.goods_price,oa.title,oa.goods_price,g.invitation_first_member,g.invitation_second_member,g.invitation_first_agent,g.invitation_second_agent')
            ->select();
        // 一级邀请者分销
        $invitation_first = $member
            ->alias('m')
            ->join('wechat w', 'm.uid=w.uid')
            ->where(['m.invitation' => $order_info->invitation_from])
            ->field('m.uid,m.invitation_from,m.agent,w.openid')
            ->find();
        if (!$invitation_first) {
            return false;
        }
        $order->startTrans();
        $invitation_result = [true];
        $invitation_first_quota  = $order_info->pay_money;
        $parent_bonus = 0;
        if ($invitation_first->agent === 1) {
            foreach ($order_goods as $goods) {
                if ($goods['invitation_first_member'] > 0) {
                    $invitation_result[]  = (bool) $distribution
                        ->isUpdate(false)
                        ->data([
                            'uid'       => $invitation_first->uid,
                            'from_uid'  => $order_info->uid,
                            'status'    => 1,
                            'level'     => 1,
                            'order_id'  => $order_info->order_id,
                            'quota'     => floor($goods['goods_price'] * ($goods['invitation_first_member'] / 100)),
                        ])
                        ->save();
                    $parent_bonus += floor($goods['goods_price'] * ($goods['invitation_first_member'] / 100));
                    $invitation_first_quota -= $goods['goods_price'];
                }
            }
            if ($invitation_first_quota > 0) {
                $invitation_result[] = (bool) $distribution
                    ->isUpdate(false)
                    ->data([
                        'uid'       => $invitation_first->uid,
                        'from_uid'  => $order_info->uid,
                        'status'    => 1,
                        'level'     => 1,
                        'order_id'  => $order_info->order_id,
                        'quota'     => $invitation_first_quota * ($ratio['member']['first'] / 100)
                    ])
                    ->save();
                $parent_bonus += $invitation_first_quota * ($ratio['member']['first'] / 100);
            }
        } else if ($invitation_first->agent === 2) {
            foreach ($order_goods as $goods) {
                if ($goods['invitation_first_agent'] > 0) {
                    $invitation_result[]  = (bool) $distribution
                        ->isUpdate(false)
                        ->data([
                            'uid'       => $invitation_first->uid,
                            'from_uid'  => $order_info->uid,
                            'status'    => 1,
                            'level'     => 1,
                            'order_id'  => $order_info->order_id,
                            'quota'     => floor($goods['goods_price'] * ($goods['invitation_first_agent'] / 100)),
                        ])
                        ->save();
                    $parent_bonus += floor($goods['goods_price'] * ($goods['invitation_first_agent'] / 100));
                    $invitation_first_quota -= $goods['goods_price'];
                }
            }
            if ($invitation_first_quota > 0) {
                $invitation_result[] = (bool) $distribution
                    ->isUpdate(false)
                    ->data([
                        'uid'       => $invitation_first->uid,
                        'from_uid'  => $order_info->uid,
                        'status'    => 1,
                        'level'     => 1,
                        'order_id'  => $order_info->order_id,
                        'quota'     => $invitation_first_quota * ($ratio['agent']['first'] / 100)
                    ])
                    ->save();
                $parent_bonus += $invitation_first_quota * ($ratio['agent']['first'] / 100);
            }
        }
        if ($invitation_first->invitation_from === 'self') {
            $order_result = $order
                ->isUpdate(true)
                ->save(['is_distribution' => 2], ['id' => $order_info->order_id]);
            if ($order_result && !in_array(false, $invitation_result)) {
                $order->commit();
                $parent_notice_data = [
                    'openid'                => $invitation_first->openid,
                    'nickname'              => $member_info->nickname,
                    'level'                 => '一级',
                    'quota'                 => sprintf("%.2f", $invitation_first_quota / 100),
                    'create_date'           => $order_info->create_date,
                    'bonus'                 => sprintf("%.2f", $parent_bonus / 100),
                    'expect_income_date'    => $order_info->expect_income_date
                ];
                WeChatTemplateMessage::consumption($parent_notice_data);
                return true;
            } else {
                $order->rollback();
            }
            return false;
        }

        // 二级邀请者分销
        $invitation_second = $member
        ->alias('m')
        ->join('wechat w', 'm.uid=w.uid')
        ->where(['m.invitation' => $invitation_first->invitation_from])
        ->field('m.uid,m.invitation_from,m.agent,w.openid')
        ->find();
        if (!$invitation_second) {
            return false;
        }
        $invitation_second_quota  = $order_info->pay_money;
        $grandpa_bonus = 0;
        if ($invitation_second->agent === 1) {
            foreach ($order_goods as $goods) {
                if ($goods['invitation_second_member'] > 0) {
                    $invitation_result[]  = (bool) $distribution
                        ->isUpdate(false)
                        ->data([
                            'uid'       => $invitation_second->uid,
                            'from_uid'  => $order_info->uid,
                            'status'    => 1,
                            'level'     => 2,
                            'order_id'  => $order_info->order_id,
                            'quota'     => floor($goods['goods_price'] * ($goods['invitation_second_member'] / 100)),
                        ])
                        ->save();
                    $grandpa_bonus += floor($goods['goods_price'] * ($goods['invitation_second_member'] / 100));
                    $invitation_second_quota -= $goods['goods_price'];
                }
            }

            if ($invitation_second_quota > 0) {
                $invitation_result[] = (bool) $distribution
                    ->isUpdate(false)
                    ->data([
                        'uid'       => $invitation_second->uid,
                        'from_uid'  => $order_info->uid,
                        'status'    => 1,
                        'level'     => 2,
                        'order_id'  => $order_info->order_id,
                        'quota'     => $invitation_second_quota * ($ratio['member']['second'] / 100)
                    ])
                    ->save();
                $grandpa_bonus  = $invitation_second_quota * ($ratio['member']['second'] / 100);
            }
        } else if ($invitation_second->agent === 2) {
            foreach ($order_goods as $goods) {
                if ($goods['invitation_second_agent'] > 0) {
                    $invitation_result[]  = (bool) $distribution
                        ->isUpdate(false)
                        ->data([
                            'uid'       => $invitation_second->uid,
                            'from_uid'  => $order_info->uid,
                            'status'    => 1,
                            'level'     => 2,
                            'order_id'  => $order_info->order_id,
                            'quota'     => floor($goods['goods_price'] * ($goods['invitation_second_agent'] / 100)),
                        ])
                        ->save();
                    $grandpa_bonus = floor($goods['goods_price'] * ($goods['invitation_second_agent'] / 100));
                    $invitation_second_quota -= $goods['goods_price'];
                }
            }
            if ($invitation_second_quota > 0) {
                $invitation_result[] = (bool) $distribution
                    ->isUpdate(false)
                    ->data([
                        'uid'       => $invitation_second->uid,
                        'from_uid'  => $order_info->uid,
                        'status'    => 1,
                        'level'     => 2,
                        'order_id'  => $order_info->order_id,
                        'quota'     => $invitation_second_quota * ($ratio['agent']['second'] / 100)
                    ])
                    ->save();
                $grandpa_bonus  = $invitation_second_quota * ($ratio['agent']['second'] / 100);
            }
        }
        $order_result = $order
            ->isUpdate(true)
            ->save(['is_distribution' => 2], ['id' => $order_info->order_id]);
        if ($order_result && !in_array(false, $invitation_result)) {
            $order->commit();
            $parent_notice_data = [
                'openid'                => $invitation_first->openid,
                'nickname'              => $member_info->nickname,
                'level'                 => '一级',
                'quota'                 => sprintf("%.2f", $invitation_first_quota / 100),
                'create_date'           => $order_info->create_date,
                'bonus'                 => sprintf("%.2f", $parent_bonus / 100),
                'expect_income_date'    => $order_info->expect_income_date
            ];
            $grandpa_notice_data = [
                'openid'             => $invitation_second->openid,
                'nickname'           => $member_info->nickname,
                'level'              => '二级',
                'quota'              => sprintf("%.2f", $invitation_second_quota / 100),
                'create_date'        => $order_info->create_date,
                'bonus'              => sprintf("%.2f", $grandpa_bonus / 100),
                'expect_income_date' => $order_info->expect_income_date
            ];
            WeChatTemplateMessage::consumption($parent_notice_data);
            WeChatTemplateMessage::consumption($grandpa_notice_data);
        } else {
            $order->rollback();
        }
        return true;
    }
}